package org.threads.threadpool;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.threads.threadpool.task.Task;
import org.threads.threadpool.task.TaskImpl;

/**
 * Model of tasks generator. Adds random task to
 * tasks queue within <code>generationInterval</code>.
 *
 * @author oler
 */
public class TaskGenerationThread implements Runnable {

    private static final Logger LOGGER = LoggerFactory.getLogger(TaskGenerationThread.class);

    /**
     * Queue with waiting tasks to be processed.
     */
    private final TasksQueue processQueue;

    /**
     * Delay between tasks generating. Have to be passed
     * to constructor.
     */
    private long generationInterval;

    /**
     * Common constructor.
     *
     * @param processQueue       queue with tasks
     * @param generationInterval delay between tasks generating
     * @throws IllegalArgumentException if processQueue is null
     */
    public TaskGenerationThread(final TasksQueue processQueue, long generationInterval)
            throws IllegalArgumentException {

        if (processQueue == null) {
            throw new IllegalArgumentException("Queue object cannot be equal to null!");
        }

        this.processQueue = processQueue;
        setGenerationInterval(generationInterval);
    }

    /**
     * Entry point, used for testing.
     *
     * @param args
     */
    public static void main(String[] args) throws InterruptedException {

        final long testingTime = 2000;
        final int poolSize = 2;
        final int generatorsCount = 3;

        final TasksQueue processQueue = new TasksQueue();

        for (int i = 0; i < poolSize; i++) {
            Thread t = new Thread(
                    new ProcessingThread(processQueue));
            t.setDaemon(true);
            t.start();
        }

        for (int i = 0; i < generatorsCount; i++) {
            Thread t = new Thread(
                    new TaskGenerationThread(processQueue, 100));
            t.setDaemon(true);
            t.start();
        }

        Thread.sleep(testingTime);
    }

    /**
     * Gets a delay between tasks generating.
     *
     * @return delay in milliseconds
     */
    public float getGenerationInterval() {
        return generationInterval;
    }

    /**
     * Sets a delay between tasks generating.
     *
     * @param generationInterval delay in milliseconds
     * @throws IllegalArgumentException if delay is less then zero
     */
    public void setGenerationInterval(long generationInterval)
            throws IllegalArgumentException {

        if (generationInterval < 0) {
            throw new IllegalArgumentException("Generation interval cannot be less then zero!");
        }

        this.generationInterval = generationInterval;
    }

    /**
     * Entry point for custom thread.
     */
    @Override
    public void run() {

        while (true) {

            synchronized (processQueue) {

                if (processQueue.isFull()) {
                    continue;
                }

                Task task = new TaskImpl();
                processQueue.addProcess(task);

                LOGGER.info(Thread.currentThread().getName() + ":  "
                        + "generated task [ " + task.getId() + " ]");

            }

            try {
                Thread.sleep(generationInterval);
            } catch (InterruptedException ex) {
                LOGGER.error(ex.toString());
            }
        }
    }

}
